package main

import (
	"bytes"
	"fmt"
	"math"
	"reflect"
	"strings"
	"time"
)

type QueryBuilder struct {
	Type reflect.Type
}

type Employee struct {
	ID        uint32 `orm:"id_pk"`
	FirstName string `orm:"first_name"`
	LastName  string `orm:"last_name"`
	Birthday  time.Time
}

type PaymentTransaction struct {
	Amount      float64 `validate:"positive"`
	Description string  `validate:"max_length:250"`
}

// Reflect包中的Type和Value的区别在与， Type只是获取interface{}类型,和Value可以获取到它的值，同事可以通过v.Type
//返回的Type类型，所以TypeOf只是用于在获取元数据时使用，而Value即可以获取它的元数据的值和类型

func main() {
	t := reflect.TypeOf(&Employee{}).Elem()
	builder := &QueryBuilder{Type: t}
	fmt.Println(builder.CreateSelectQuery())
}

func (qb *QueryBuilder) CreateSelectQuery() string {
	buffer := bytes.NewBufferString("")
	//应该先判断qb.Type的类型是否为struct, 否则抛出异常
	for index := 0; index < qb.Type.NumField(); index++ {
		field := qb.Type.Field(index) //StructField 描述struct单个字段的信息

		if index == 0 {
			buffer.WriteString("SELECT ")
		} else {
			buffer.WriteString(", ")
		}
		column := field.Name
		if tag := field.Tag.Get("orm"); tag != "" {
			column = tag
		}

		buffer.WriteString(column)
	}

	if buffer.Len() > 0 {
		fmt.Fprintf(buffer, " FROM %s", qb.Type.Name())
	}

	return buffer.String()
}

func Validate(obj interface{}) error {
	v := reflect.ValueOf(obj).Elem()
	t := v.Type()

	for index := 0; index < v.NumField(); index++ {
		vField := v.Field(index)
		tField := t.Field(index)

		tag := tField.Tag.Get("validate")
		if tag == "" {
			continue
		}

		switch vField.Kind() {
		case reflect.Float64:
			value := vField.Float()
			if tag == "positive" && value < 0 {
				value = math.Abs(value)
				vField.SetFloat(value)
			}
		case reflect.String:
			value := vField.String()
			if tag == "upper_case" {
				value = strings.ToUpper(value)
				vField.SetString(value)
			}
		default:
			return fmt.Errorf("Unsupported kind '%s'", vField.Kind())
		}
	}

	return nil
}
